C# 异步编程 await async

您所在的位置:网站首页 react async await异步请求 C# 异步编程 await async

C# 异步编程 await async

2023-03-18 21:07| 来源: 网络整理| 查看: 265

和我一起跟随杨中科老师学习吧!!!

目录

1.如何理解同步和异步

2.异步编程项目实例以及一些关键字强调点:

3.async、await的原理揭晓

4.异步方法不等于多线程

5.没有Async关键字的public Task functionAsync(){}是什么情况

6.sleep

7.如果有些地方没有做到能够通过async、await实现异步,但是又不得不用,怎么处理?使用result或者wait()

异步编程--await、async的基本使用

如何理解同步和异步:

首先先了解数据通信交互原理: web浏览器(客户端)发起请求--服务器处理本次请求--处理结果响应到客户端

然后理解同步:客户端(相当于浏览器,可以理解为调用者)发起一个请求,客户端在没有得到结果之前,客户端不继续执行后续操作

再理解异步:异步与同步相对。当一个异步调用过程发出后,调用者在没有得到返回结果之前,可以继续执行后续操作。当这个调用完成后,会通过轮询、消息和回调来通知调用者

加深理解、实例解说:异步并没有提高单个用户请求的响应时间。同步和异步的关系就如同传统店内点餐和如今扫码点餐的区别;单桌顾客菜品的制作时间(也就是响应时间: 是指服务器对请求做出响应的时间)没有变化,区别只在于能兼顾多桌顾客同时点餐,也就是提高的是服务器接收请求的次数

异步编程项目实例以及一些强调点:

一些需要强调的地方:

异步方法一般命名会在方法名尾部加上async,但更准确的判断方法是看方法的返回数据类型是不是Task,如果返回数据类型是Task,那么不管方法名有没有async,这个方法就是异步方法

方法中只要调用了异步方法,异步方法前就要加上await,否则此调用不会等待,因此在此调用完成之前会继续执行当前方法

调用的异步方法前加上await,异步方法返回的值会自动从Task数据类型转换为相应的数据类型,不用额外进行数据类型转换

方法中如果调用了异步方法,那根据传染法则,这个方法也要写为异步类型public async Task fn(){}

异步方法是通过async关键词来实现的,但是数据类型不能写为void,应该写为Task,否则运行以后会报错,提示程序不包含入口的静态main方法

//异步 static async Task Main(string[] args) { 同步 //string path = @"E:\text2.txt"; //File.WriteAllText(path, "hello world"); //string s = File.ReadAllText(path); //Console.WriteLine(s); //异步 string path = @"E:\text3.txt"; await File.WriteAllTextAsync(path, "hello world hello world"); string s = await File.ReadAllTextAsync(path); Console.WriteLine(s); }

async、await的原理揭晓

通过反编译代码分析async/await原理

找到当前类的编译文件.dll,在ILSpy反编译器上进行反编译

为什么运行的文件是.exe文件,反编译时确是.dll文件,因为.net Core是跨平台的,所以这个程序我们可以拷贝到linux或者苹果系统下面的,但是.exe是windows独有的格式,所以.exe只是window平台下的一个启动器,反编译.exe是反编译不出什么有价值的东西的

async背后的线程切换

await调用等待过程中,.net会把线程返回给线程池,当异步方法调用执行完成后,框架会从程序池再取一个线程执行后续的代码

可以跟踪测试

首先,使用Thread.CurrentThread.ManagedThreadId来获得当前线程ID

当异步调用方法等待时间较短时,线程id有可能是一样的,这个取决于电脑的性能

异步方法不等于多线程

异步方法的代码不会在新线程上执行,除非把代码放到新线程上执行

多线程是实现异步的手段,但不能说他们是一回事,只有一个线程也可以实现异步,更详细讲解可以参考https://zhuanlan.zhihu.com/p/570792890

没有Async关键字的public Task functionAsync(){}是什么情况

方法体中没有用到await就可以不写Async关键字

public Task functionAsync(){return File.ReadAllTextAsync(path)}

等价于:public Async Task functionAsync(){string s = await File.ReadAllTextAsync(path); return s;}

不写async、await方法有什么区别吗

加不加async是一样的,但是写了async后加不加await是不一样的。

写async、await和不写async、await逻辑上是一样的,但是运行上是不一样的。一是:await会带来上下文切换;二是:await需要捕获当前的运行上下文,以便随后重施。但捕获也带来了额外的开销

所以异步方法的运行速度会比普通方法慢,而且很可能会开启多个线程

sleep

异步方法中不要使用sleep,会阻塞调用线程/主线程,睡眠的时间,页面将无法进行任何操作。

但是Sleep会降低并发

使用Task.Delay()

可以通过示例实验。在控制台上不是很能做测试示例,在winform项目下测试sleep和Task.Delay的区别,创建一个按钮和一个textBox。在控制台看不到区别,因为控制台没有一个明显的UI线程。包括asp .net core也看不到明显的区别,但是sleep会阻塞web服务器的线程,程序会卡住,会大大降低web服务器的并发。对服务器影响特别大,一定要注意使用sleep()

public void button_click()

{

using(HttpClient httpClient = new HttpClient())

{

string s1 = await httpClient.GetStringAsync("https://www.baidu.com");

textBox.Text = s1.subString(0,100);

//Thread.Sleep(3000);

await Task.Delay(3000);

string s1 = await httpClient.GetStringAsync("https://www.sina.com");

textBox.Text = s1.subString(0,100);

}

}

一些概念

什么叫响应时间:

是指服务器对请求做出响应的时间。

对于单机的没有并发操作的应用系统而言,人们认为响应时间是一个合理并准确的性能指标

什么叫吞吐量:

是指服务器在1秒的时间内能够处理请求的数量

如果两个具有不同用户数量以及用户使用模式的系统,他们的最大吞吐量基本一致的,那么可以证明这两个系统的处理能力基本一致

什么叫并发用户数

是指在同一时间对服务器发出请求的用户数量。

不是使用系统的全部用户量,也不是在线用户数量。在线用户不一定会和其他用户产生并发,比如用户在浏览网页,对服务器是没有任何影响的。因此,并发用户数的真正含义是在同一时间段内与服务器发生交互的在线用户数量

如果有些地方没有做到能够通过async、await实现异步,但是又不得不用,怎么处理

不适用async、await,使用result或者wait()

有返回值就使用result,没有返回值,只是执行语句就使用wait()

但是尽量不要用,因为它有死锁的风险

string s1 = await File.ReadAllTextAsync(path); Console.WriteLine(s1); 上面两行代码等价于下面代码:         //File.WriteAllTextAsync(path).wait(); Task taskText = File.ReadAllTextAsync(path); string s2 = taskText.Result; Console.WriteLine(s2);

拓展1

File方法:File.WriteAllTextAsync()/File.ReadAllTextAsync()

HttpClient方法

HttpClient是在C#中发送HTTP请求

HttpClient.GetStringAsync(url):GetStringAsync是一种简化的http请求,可以通过HttpClient中GetStringAsync便可以获得请求返回的字符串数据

参考网址:https://learn.microsoft.com/zh-cn/dotnet/api/system.net.http.httpclient.getasync?redirectedfrom=MSDN&view=net-7.0#System_Net_Http_HttpClient_GetAsync_System_String_

实例编写如下:

实例代码这里为什么要用到using(){},因为非托管代码要及时回收

static async Task Main(string[] args) { //对httpclient的理解与应用 string path = @"E:\text5.txt"; string url = @"https://www.baidu.com/"; await getUrlText(path, url); Console.WriteLine("ok"); } static async Task getUrlText(string path,string url) { using (HttpClient httpClient =new HttpClient()) { string html = await httpClient.GetStringAsync(url); await File.WriteAllTextAsync(path, html); } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3